home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / Asuka / source / glc_nvrc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-11-29  |  24.8 KB  |  906 lines

  1. #include "stdafx.h"
  2. #include "glc.h"
  3. #include <vd2/system/vdalloc.h>
  4. #include <vd2/Riza/opengl.h>
  5.  
  6. using namespace GLCIL;
  7.  
  8. namespace {
  9.     struct RegisterCombinerSrc {
  10.         uint16    mReg;
  11.         uint16    mMapping;
  12.         uint16    mPortion;
  13.  
  14.         void SetZero() { 
  15.             mReg = GL_ZERO;
  16.             mMapping = GL_SIGNED_IDENTITY_NV;
  17.             mPortion = GL_RGBA;
  18.         }
  19.  
  20.         void SetOne() { 
  21.             mReg = GL_ZERO;
  22.             mMapping = GL_UNSIGNED_INVERT_NV;
  23.             mPortion = GL_RGBA;
  24.         }
  25.  
  26.         void SetMinusOne() {
  27.             mReg = GL_ZERO;
  28.             mMapping = GL_EXPAND_NORMAL_NV;
  29.             mPortion = GL_RGBA;
  30.         }
  31.  
  32.         void Print(uint16 defaultPortion) const {
  33.             const char *s = "zero";
  34.  
  35.             switch(mReg) {
  36.                 case GL_SPARE0_NV:                s = "r0"; break;
  37.                 case GL_SPARE1_NV:                s = "r1"; break;
  38.                 case GL_PRIMARY_COLOR_NV:        s = "v0"; break;
  39.                 case GL_SECONDARY_COLOR_NV:        s = "v1"; break;
  40.                 case GL_TEXTURE0_ARB:            s = "t0"; break;
  41.                 case GL_TEXTURE1_ARB:            s = "t1"; break;
  42.                 case GL_TEXTURE2_ARB:            s = "t2"; break;
  43.                 case GL_TEXTURE3_ARB:            s = "t3"; break;
  44.                 case GL_CONSTANT_COLOR0_NV:        s = "c0"; break;
  45.                 case GL_CONSTANT_COLOR1_NV:        s = "c1"; break;
  46.             }
  47.  
  48.             switch(mMapping) {
  49.                 case GL_UNSIGNED_IDENTITY_NV:    printf("%s_sat", s); break;
  50.                 case GL_UNSIGNED_INVERT_NV:        printf("1-%s", s); break;
  51.                 case GL_SIGNED_IDENTITY_NV:        printf("%s", s); break;
  52.                 case GL_SIGNED_NEGATE_NV:        printf("-%s", s); break;
  53.                 case GL_EXPAND_NORMAL_NV:        printf("%s_bx2", s); break;
  54.                 case GL_EXPAND_NEGATE_NV:        printf("-%s_bx2", s); break;
  55.                 case GL_HALF_BIAS_NORMAL_NV:    printf("%s_bias", s); break;
  56.                 case GL_HALF_BIAS_NEGATE_NV:    printf("-%s_bias", s); break;
  57.             }
  58.  
  59.             if (mPortion != defaultPortion) {
  60.                 switch(mPortion) {
  61.                     case GL_RGB:
  62.                         printf(".rgb");
  63.                         break;
  64.                     case GL_ALPHA:
  65.                         printf(".a");
  66.                         break;
  67.                     case GL_BLUE:
  68.                         printf(".b");
  69.                         break;
  70.                 }
  71.             }
  72.         }
  73.  
  74.         static uint8 GetRegisterCode(uint16 reg) {
  75.             uint8 code;
  76.  
  77.             switch(reg) {
  78.                 case GL_ZERO:                    code = 0x00; break;
  79.                 case GL_DISCARD_NV:                code = 0x01; break;
  80.                 case GL_SPARE0_NV:                code = 0x02; break;
  81.                 case GL_SPARE1_NV:                code = 0x03; break;
  82.                 case GL_PRIMARY_COLOR_NV:        code = 0x04; break;
  83.                 case GL_SECONDARY_COLOR_NV:        code = 0x05; break;
  84.                 case GL_CONSTANT_COLOR0_NV:        code = 0x06; break;
  85.                 case GL_CONSTANT_COLOR1_NV:        code = 0x07; break;
  86.                 case GL_SPARE0_PLUS_SECONDARY_COLOR_NV:        code = 0x08; break;
  87.                 case GL_E_TIMES_F_NV:            code = 0x09; break;
  88.                 case GL_TEXTURE0_ARB:            code = 0x0C; break;
  89.                 case GL_TEXTURE1_ARB:            code = 0x0D; break;
  90.                 case GL_TEXTURE2_ARB:            code = 0x0E; break;
  91.                 case GL_TEXTURE3_ARB:            code = 0x0F; break;
  92.             }
  93.  
  94.             return code;
  95.         }
  96.  
  97.         void Write(FILE *f) const {
  98.             uint8 code = GetRegisterCode(mReg);
  99.  
  100.             switch(mMapping) {
  101.                 case GL_UNSIGNED_IDENTITY_NV:    break;
  102.                 case GL_UNSIGNED_INVERT_NV:        code |= 0x10; break;
  103.                 case GL_SIGNED_IDENTITY_NV:        code |= 0x20; break;
  104.                 case GL_SIGNED_NEGATE_NV:        code |= 0x30; break;
  105.                 case GL_EXPAND_NORMAL_NV:        code |= 0x40; break;
  106.                 case GL_EXPAND_NEGATE_NV:        code |= 0x50; break;
  107.                 case GL_HALF_BIAS_NORMAL_NV:    code |= 0x60; break;
  108.                 case GL_HALF_BIAS_NEGATE_NV:    code |= 0x70; break;
  109.             }
  110.  
  111.             if (mPortion == GL_ALPHA)
  112.                 code |= 0x80;
  113.  
  114.             fprintf(f, "0x%02x", code);
  115.         }
  116.     };
  117.  
  118.     struct RegisterCombinerHalf {
  119.         uint16    mDst[3];
  120.         uint16    mScale;
  121.         uint16    mBias;
  122.         RegisterCombinerSrc    mSrc[4];
  123.         bool    mbDotAB;
  124.         bool    mbDotCD;
  125.         bool    mbMux;
  126.  
  127.         RegisterCombinerHalf() {
  128.             mDst[0] = mDst[1] = mDst[2] = GL_DISCARD_NV;
  129.             mScale = GL_NONE;
  130.             mBias = GL_NONE;
  131.             mSrc[0].SetZero();
  132.             mSrc[1].SetZero();
  133.             mSrc[2].SetZero();
  134.             mSrc[3].SetZero();
  135.             mbDotAB = false;
  136.             mbDotCD = false;
  137.             mbMux = false;
  138.         }
  139.  
  140.         void Write(FILE *f) {
  141.             uint8 scaleBiasCode = 0;
  142.  
  143.             if (mBias == GL_BIAS_BY_NEGATIVE_ONE_HALF_NV) {
  144.                 if (mScale == GL_SCALE_BY_TWO_NV)
  145.                     scaleBiasCode = 5;
  146.                 else
  147.                     scaleBiasCode = 4;
  148.             } else {
  149.                 switch(mScale) {
  150.                     case GL_SCALE_BY_TWO_NV:
  151.                         scaleBiasCode = 1;
  152.                         break;
  153.                     case GL_SCALE_BY_FOUR_NV:
  154.                         scaleBiasCode = 2;
  155.                         break;
  156.                     case GL_SCALE_BY_ONE_HALF_NV:
  157.                         scaleBiasCode = 3;
  158.                         break;
  159.                 }
  160.             }
  161.  
  162.             uint8 dst0Code = RegisterCombinerSrc::GetRegisterCode(mDst[0]);
  163.             uint8 dst1Code = RegisterCombinerSrc::GetRegisterCode(mDst[1]);
  164.             uint8 dst2Code = RegisterCombinerSrc::GetRegisterCode(mDst[2]);
  165.  
  166.             fprintf(f, "0x%02x,0x%02x,", scaleBiasCode + (dst0Code << 4), dst1Code + (dst2Code << 4));
  167.             fprintf(f, "0x%02x,", (mbDotAB ? 1 : 0) + (mbDotCD ? 2 : 0) + (mbMux ? 4 : 0));
  168.  
  169.             for(int i=0; i<4; ++i) {
  170.                 mSrc[i].Write(f);
  171.                 putc(',', f);
  172.             }
  173.         }
  174.     };
  175.  
  176.     struct RegisterCombiner {
  177.         RegisterCombinerHalf mColor;
  178.         RegisterCombinerHalf mAlpha;
  179.         int mConstantMapping[2];
  180.  
  181.         RegisterCombiner() {
  182.             mConstantMapping[0] = -1;
  183.             mConstantMapping[1] = -1;
  184.         }
  185.  
  186.         void Write(FILE *f, bool rc2) {
  187.             if (rc2)
  188.                 fprintf(f, "\t0x%02x,0x%02x,", (uint8)mConstantMapping[0], (uint8)mConstantMapping[1]);
  189.             mColor.Write(f);
  190.             mAlpha.Write(f);
  191.             putc('\n', f);
  192.         }
  193.     };
  194.  
  195.     struct RegisterCombinerFinal {
  196.         RegisterCombinerSrc mSrc[7];
  197.         int mConstantMapping[2];
  198.  
  199.         RegisterCombinerFinal() {
  200.             mConstantMapping[0] = -1;
  201.             mConstantMapping[1] = -1;
  202.             mSrc[0].SetZero();
  203.             mSrc[0].mMapping = GL_UNSIGNED_IDENTITY_NV;
  204.             mSrc[1].mReg = GL_SPARE0_NV;
  205.             mSrc[1].mMapping = GL_UNSIGNED_IDENTITY_NV;
  206.             mSrc[1].mPortion = GL_RGB;
  207.             mSrc[2] = mSrc[1];
  208.             mSrc[3].SetZero();
  209.             mSrc[3].mMapping = GL_UNSIGNED_IDENTITY_NV;
  210.             mSrc[4].SetZero();
  211.             mSrc[4].mMapping = GL_UNSIGNED_IDENTITY_NV;
  212.             mSrc[5].SetZero();
  213.             mSrc[5].mMapping = GL_UNSIGNED_IDENTITY_NV;
  214.             mSrc[6].mReg = GL_SPARE0_NV;
  215.             mSrc[6].mMapping = GL_UNSIGNED_IDENTITY_NV;
  216.             mSrc[6].mPortion = GL_ALPHA;
  217.         }
  218.  
  219.         void Write(FILE *f, bool rc2) {
  220.             fputc('\t', f);
  221.             if (rc2)
  222.                 fprintf(f, "0x%02x,0x%02x,", (uint8)mConstantMapping[0], (uint8)mConstantMapping[1]);
  223.  
  224.             for(int i=0; i<7; ++i) {
  225.                 mSrc[i].Write(f);
  226.                 fputc(',', f);
  227.             }
  228.             fputc('\n', f);
  229.         }
  230.     };
  231.  
  232.     class RegisterCombinerConfig : public vdrefcounted<IGLCFragmentShader> {
  233.     public:
  234.         RegisterCombinerConfig()
  235.             : mGeneralCombinerCount(0)
  236.             , mConstantsUsed(0)
  237.         {
  238.             memset(mConstants, 0, sizeof mConstants);
  239.         }
  240.  
  241.         const char *GetTypeString() {
  242.             return mConstantsUsed <= 2 && mGeneralCombinerCount <= 2 ? "kVDOpenGLFragmentShaderModeNVRC" : "kVDOpenGLFragmentShaderModeNVRC2";
  243.         }
  244.  
  245.         void Write(FILE *f, const char *sym) {
  246.             if (mConstantsUsed > 0) {
  247.                 fprintf(f, "static const float %s_constants[][4]={\n", sym, mConstantsUsed);
  248.                 for(int i=0; i<mConstantsUsed; ++i) {
  249.                     fprintf(f, "\t{");
  250.  
  251.                     for(int j=0; j<4; ++j) {
  252.                         char buf[512];
  253.                         sprintf(buf, "%g", mConstants[i][j]);
  254.                         if (strchr(buf, '.'))
  255.                             fprintf(f, " %sf", buf);
  256.                         else
  257.                             fprintf(f, " %s.f", buf);
  258.  
  259.                         if (j != 3)
  260.                             putc(',', f);
  261.                     }
  262.  
  263.                     fprintf(f, " },\n");
  264.                 };
  265.                 fprintf(f, "};\n");
  266.             }
  267.  
  268.             bool rc2 = mConstantsUsed > 2 || mGeneralCombinerCount > 2;
  269.             fprintf(f, "static const uint8 %s_bytecode[]={\n", sym);
  270.             for(int i=0; i<mGeneralCombinerCount; ++i)
  271.                 mGeneralCombiners[i].Write(f, rc2);
  272.             mFinalCombiner.Write(f, rc2);
  273.             fprintf(f, "};\n");
  274.  
  275.             fprintf(f, "static const struct VDOpenGLNVRegisterCombinerConfig %s={\n", sym);
  276.             fprintf(f, "\t%d, ", mConstantsUsed);
  277.             fprintf(f, "%d, ", mGeneralCombinerCount);
  278.             if (mConstantsUsed > 0)
  279.                 fprintf(f, "%s_constants, ", sym);
  280.             else
  281.                 fprintf(f, "NULL, ");
  282.             fprintf(f, "%s_bytecode\n", sym);
  283.             fprintf(f, "};\n");
  284.         }
  285.  
  286.     public:
  287.         RegisterCombiner        mGeneralCombiners[8];
  288.         RegisterCombinerFinal    mFinalCombiner;
  289.         float    mConstants[16][4];
  290.         int mConstantsUsed;
  291.         int mGeneralCombinerCount;
  292.     };
  293. }
  294.  
  295. IGLCFragmentShader *CompileFragmentShaderNVRegisterCombiners(GLCErrorSink& errout, const GLCFragmentShader& shader, bool NV_register_combiners_2) {
  296.     int combinerLimit = NV_register_combiners_2 ? 8 : 2;
  297.  
  298.     if (!NV_register_combiners_2 && shader.mUsedConstants > 3)
  299.         errout.ThrowError(shader.mLocation, "NV_register_combiners only allows two constant registers");
  300.  
  301.     GLCFragmentShader::FragmentOps::const_iterator it(shader.mOps.begin()), itEnd(shader.mOps.end());
  302.     bool seenFinalCombiner = false;
  303.     int constantStageMask = 0;
  304.     int constantStageCount = 0;
  305.     int combinerOutputMask = 0;
  306.     bool combinerAlphaOp = false;
  307.     bool combinerColorOp = false;
  308.  
  309.     vdautoptr<RegisterCombinerConfig> config(new RegisterCombinerConfig);
  310.     RegisterCombiner *pCombiner = config->mGeneralCombiners;
  311.  
  312.     int constantMapping[16]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
  313.  
  314.     while(it!=itEnd) {
  315.         const GLCFragmentOp& op = *it;
  316.         bool isFinalCombiner = op.mInsn == kFSOpFinal;
  317.  
  318.         if (isFinalCombiner) {
  319.             if (seenFinalCombiner)
  320.                 errout.ThrowError(op.mLocation, "Final combiner already configured");
  321.  
  322.             seenFinalCombiner = true;
  323.         } else {
  324.             if (config->mGeneralCombinerCount >= combinerLimit)
  325.                 errout.ThrowError(shader.mLocation, "Exceeded instruction count limit for profile (%d max)\n", combinerLimit);
  326.         }
  327.  
  328.         // convert sources
  329.         RegisterCombinerSrc rsrcs[7];
  330.         bool allowAlpha = true;
  331.         bool allowColor = true;
  332.  
  333.         for(int i=0; i<7; ++i) {
  334.             const GLCSourceArg& opsrc = op.mSrcArgs[i];
  335.             RegisterCombinerSrc& rsrc = rsrcs[i];
  336.             int reg = opsrc.mReg;
  337.  
  338.             // map register
  339.             switch(opsrc.mReg & kRegTypeMask) {
  340.                 case 0:
  341.                     rsrc.mReg = 0;
  342.                     break;
  343.                 case kRegZero:
  344.                     rsrc.mReg = GL_ZERO;
  345.                     break;
  346.                 case kRegC0:
  347.                     {
  348.                         int index = reg - kRegC0;
  349.  
  350.                         if (constantMapping[index] == -1) {
  351.                             constantMapping[index] = config->mConstantsUsed;
  352.                             memcpy(config->mConstants[config->mConstantsUsed], shader.mConstants[index], sizeof(float)*4);
  353.                             index = config->mConstantsUsed++;
  354.                         }
  355.  
  356.                         if (NV_register_combiners_2) {
  357.                             int *mappings = isFinalCombiner ? config->mFinalCombiner.mConstantMapping : pCombiner->mConstantMapping;
  358.  
  359.                             if (index == mappings[0])
  360.                                 rsrc.mReg = GL_CONSTANT_COLOR0_NV;
  361.                             else if (index == mappings[1])
  362.                                 rsrc.mReg = GL_CONSTANT_COLOR1_NV;
  363.                             else if (mappings[0] == -1) {
  364.                                 mappings[0] = index;
  365.                                 rsrc.mReg = GL_CONSTANT_COLOR0_NV;
  366.                             } else if (mappings[1] == -1) {
  367.                                 mappings[1] = index;
  368.                                 rsrc.mReg = GL_CONSTANT_COLOR1_NV;
  369.                             } else
  370.                                 errout.ThrowError(op.mLocation, "Too many constants used in combiner stage (2 max)");
  371.                         } else {
  372.                             rsrc.mReg = index ? GL_CONSTANT_COLOR1_NV : GL_CONSTANT_COLOR0_NV;
  373.                         }
  374.                     }
  375.                     break;
  376.                 case kRegV0:
  377.                     if (opsrc.mReg == kRegV0)
  378.                         rsrc.mReg = GL_PRIMARY_COLOR_NV;
  379.                     else
  380.                         rsrc.mReg = GL_SECONDARY_COLOR_NV;
  381.                     break;
  382.                 case kRegR0:
  383.                     if (opsrc.mReg - kRegR0 >= 2)
  384.                         errout.ThrowError(op.mLocation, "Invalid spare register (max 2)");
  385.  
  386.                     if (opsrc.mReg == kRegR0)
  387.                         rsrc.mReg = GL_SPARE0_NV;
  388.                     else
  389.                         rsrc.mReg = GL_SPARE1_NV;
  390.                     break;
  391.  
  392.                 case kRegT0:
  393.                     if (opsrc.mReg - kRegT0 >= 4)
  394.                         errout.ThrowError(op.mLocation, "Invalid spare register (max 2)");
  395.  
  396.                     rsrc.mReg = GL_TEXTURE0_ARB + (opsrc.mReg - kRegT0);
  397.                     break;
  398.  
  399.                 default:
  400.                     errout.ThrowError(op.mLocation, "Internal error");
  401.             }
  402.  
  403.             // map swizzle
  404.             if (opsrc.mSwizzle == kSwizzleNone || opsrc.mReg == 0)
  405.                 rsrc.mPortion = GL_RGBA;
  406.             else if (opsrc.mSwizzle == kSwizzleRGB && opsrc.mSize == 3) {
  407.                 rsrc.mPortion = GL_RGB;
  408.                 allowAlpha = false;
  409.             } else if (opsrc.mSwizzle == kSwizzleAlpha)
  410.                 rsrc.mPortion = GL_ALPHA;
  411.             else if (opsrc.mSwizzle == kSwizzleBlue) {
  412.                 rsrc.mPortion = GL_BLUE;
  413.                 allowColor = false;
  414.             } else
  415.                 errout.ThrowError(op.mLocation, "Swizzle not allowed in this profile: must be .a, .b, .rgb, or .rgba (none)");
  416.  
  417.             // map modifiers
  418.             switch(opsrc.mMods) {
  419.             case 0:
  420.                 rsrc.mMapping = GL_SIGNED_IDENTITY_NV;
  421.                 break;
  422.             case kRegModNegate:
  423.                 rsrc.mMapping = GL_SIGNED_NEGATE_NV;
  424.                 break;
  425.             case kRegModSaturate:
  426.                 rsrc.mMapping = GL_UNSIGNED_IDENTITY_NV;
  427.                 break;
  428.             case kRegModComplement:
  429.             case kRegModSaturate | kRegModComplement:
  430.                 rsrc.mMapping = GL_UNSIGNED_INVERT_NV;
  431.                 break;
  432.             case kRegModBias | kRegModX2:
  433.                 rsrc.mMapping = GL_EXPAND_NORMAL_NV;
  434.                 break;
  435.             case kRegModBias | kRegModX2 | kRegModNegate:
  436.                 rsrc.mMapping = GL_EXPAND_NEGATE_NV;
  437.                 break;
  438.             case kRegModBias:
  439.                 rsrc.mMapping = GL_HALF_BIAS_NORMAL_NV;
  440.                 break;
  441.             case kRegModBias | kRegModNegate:
  442.                 rsrc.mMapping = GL_HALF_BIAS_NEGATE_NV;
  443.                 break;
  444.             default:
  445.                 errout.ThrowError(op.mLocation, "Unsupported source modifier");
  446.                 break;
  447.             }
  448.         }
  449.  
  450.         if (!isFinalCombiner) {
  451.             // sanity check and convert destinations
  452.             int dstMask = 0;
  453.             uint16 rdsts[3];
  454.  
  455.             for(int dst=0; dst<3; ++dst) {
  456.                 int reg = op.mDstArgs[dst].mReg;
  457.  
  458.                 rdsts[dst] = GL_DISCARD_NV;
  459.  
  460.                 if (reg && reg != kRegDiscard) {
  461.                     int regMask = op.mDstArgs[dst].mWriteMask;
  462.                     if (!dstMask)
  463.                         dstMask = regMask;
  464.                     else if (dstMask != regMask)
  465.                         errout.ThrowError(op.mLocation, "Inconsistent destination write masks");
  466.  
  467.                     switch(reg & kRegTypeMask) {
  468.                         case kRegC0:
  469.                             errout.ThrowError(op.mLocation, "Constant register cannot be used as destination");
  470.                             break;
  471.                         case kRegV0:
  472.                             errout.ThrowError(op.mLocation, "Interpolator register cannot be used as destination");
  473.                             break;
  474.                         case kRegT0:
  475.                             rdsts[dst] = GL_TEXTURE0_ARB + (reg - kRegT0);
  476.                             break;
  477.                         case kRegR0:
  478.                             if (reg - kRegR0 >= 2)
  479.                                 errout.ThrowError(op.mLocation, "Invalid spare register (max 2)");
  480.  
  481.                             rdsts[dst] = GL_SPARE0_NV + (reg - kRegR0);
  482.                             break;
  483.                         default:
  484.                             errout.ThrowError(op.mLocation, "Invalid destination register");
  485.                     }
  486.                 }
  487.             }
  488.  
  489.             // assign to color and alpha combiner halves
  490.             bool colorOp = false;
  491.             bool alphaOp = false;
  492.  
  493.             switch(dstMask) {
  494.                 case 7:
  495.                     colorOp = true;
  496.                     break;
  497.                 case 8:
  498.                     alphaOp = true;
  499.                     break;
  500.                 case 15:
  501.                     alphaOp = true;
  502.                     colorOp = true;
  503.                     break;
  504.                 default:
  505.                     errout.ThrowError(op.mLocation, "Invalid destination write mask. Must be one of: .rgb, .a, none (.rgba)");
  506.             }
  507.  
  508.             // convert instruction modifiers
  509.             RegisterCombinerHalf chalf;
  510.  
  511.             switch(op.mModifiers) {
  512.                 case 0:
  513.                     chalf.mScale = GL_NONE;
  514.                     chalf.mBias = GL_NONE;
  515.                     break;
  516.                 case kInsnModD2:
  517.                     chalf.mScale = GL_SCALE_BY_ONE_HALF_NV;
  518.                     chalf.mBias = GL_NONE;
  519.                     break;
  520.                 case kInsnModX2:
  521.                     chalf.mScale = GL_SCALE_BY_TWO_NV;
  522.                     chalf.mBias = GL_NONE;
  523.                     break;
  524.                 case kInsnModX4:
  525.                     chalf.mScale = GL_SCALE_BY_FOUR_NV;
  526.                     chalf.mBias = GL_NONE;
  527.                     break;
  528.                 case kInsnModBias:
  529.                     chalf.mScale = GL_NONE;
  530.                     chalf.mBias = GL_BIAS_BY_NEGATIVE_ONE_HALF_NV;
  531.                     break;
  532.                 case kInsnModBX2:
  533.                     chalf.mScale = GL_SCALE_BY_TWO_NV;
  534.                     chalf.mBias = GL_BIAS_BY_NEGATIVE_ONE_HALF_NV;
  535.                     break;
  536.                 default:
  537.                     errout.ThrowError(op.mLocation, "Unsupported instruction modifier");
  538.             }
  539.  
  540.             // create combiner configuration
  541.             switch(op.mInsn) {
  542.                 case kFSOpMov:
  543.                     // A*1 + B*0
  544.                     chalf.mDst[0] = rdsts[0];
  545.                     chalf.mDst[1] = GL_DISCARD_NV;
  546.                     chalf.mDst[2] = GL_DISCARD_NV;
  547.                     chalf.mSrc[0] = rsrcs[0];
  548.                     chalf.mSrc[1].SetOne();
  549.                     chalf.mSrc[2].SetZero();
  550.                     chalf.mSrc[3].SetZero();
  551.                     chalf.mbDotAB = false;
  552.                     chalf.mbDotCD = false;
  553.                     chalf.mbMux = false;
  554.                     break;
  555.                 case kFSOpAdd:
  556.                     // A*1 + B*1
  557.                     chalf.mDst[0] = GL_DISCARD_NV;
  558.                     chalf.mDst[1] = GL_DISCARD_NV;
  559.                     chalf.mDst[2] = rdsts[0];
  560.                     chalf.mSrc[0] = rsrcs[0];
  561.                     chalf.mSrc[1].SetOne();
  562.                     chalf.mSrc[2] = rsrcs[1];
  563.                     chalf.mSrc[3].SetOne();
  564.                     chalf.mbDotAB = false;
  565.                     chalf.mbDotCD = false;
  566.                     chalf.mbMux = false;
  567.                     break;
  568.                 case kFSOpSub:
  569.                     // A*1 + B*-1
  570.                     chalf.mDst[0] = GL_DISCARD_NV;
  571.                     chalf.mDst[1] = GL_DISCARD_NV;
  572.                     chalf.mDst[2] = rdsts[0];
  573.                     chalf.mSrc[0] = rsrcs[0];
  574.                     chalf.mSrc[1].SetOne();
  575.                     chalf.mSrc[2] = rsrcs[1];
  576.                     chalf.mSrc[3].SetMinusOne();
  577.                     chalf.mbDotAB = false;
  578.                     chalf.mbDotCD = false;
  579.                     chalf.mbMux = false;
  580.                     break;
  581.                 case kFSOpMul:
  582.                     // A*B + 0*0
  583.                     chalf.mDst[0] = rdsts[0];
  584.                     chalf.mDst[1] = GL_DISCARD_NV;
  585.                     chalf.mDst[2] = GL_DISCARD_NV;
  586.                     chalf.mSrc[0] = rsrcs[0];
  587.                     chalf.mSrc[1] = rsrcs[1];
  588.                     chalf.mSrc[2].SetZero();
  589.                     chalf.mSrc[3].SetZero();
  590.                     chalf.mbDotAB = false;
  591.                     chalf.mbDotCD = false;
  592.                     chalf.mbMux = false;
  593.                     break;
  594.                 case kFSOpMad:
  595.                     // A*B + C*0
  596.                     chalf.mDst[0] = GL_DISCARD_NV;
  597.                     chalf.mDst[1] = GL_DISCARD_NV;
  598.                     chalf.mDst[2] = rdsts[0];
  599.                     chalf.mSrc[0] = rsrcs[0];
  600.                     chalf.mSrc[1] = rsrcs[1];
  601.                     chalf.mSrc[2] = rsrcs[2];
  602.                     chalf.mSrc[3].SetOne();
  603.                     chalf.mbDotAB = false;
  604.                     chalf.mbDotCD = false;
  605.                     chalf.mbMux = false;
  606.                     break;
  607.                 case kFSOpLrp:
  608.                     // A*B + (1-A)*C
  609.                     chalf.mDst[0] = GL_DISCARD_NV;
  610.                     chalf.mDst[1] = GL_DISCARD_NV;
  611.                     chalf.mDst[2] = rdsts[0];
  612.                     chalf.mSrc[0] = rsrcs[0];
  613.                     chalf.mSrc[1] = rsrcs[1];
  614.                     chalf.mSrc[2] = rsrcs[0];
  615.                     chalf.mSrc[3] = rsrcs[2];
  616.  
  617.                     switch(chalf.mSrc[0].mMapping) {
  618.                     case GL_UNSIGNED_IDENTITY_NV:        // _sat
  619.                     case GL_SIGNED_IDENTITY_NV:            // (none)
  620.                         chalf.mSrc[0].mMapping = GL_UNSIGNED_IDENTITY_NV;
  621.                         chalf.mSrc[2].mMapping = GL_UNSIGNED_INVERT_NV;
  622.                         break;
  623.  
  624.                     case GL_UNSIGNED_INVERT_NV:            // 1-reg
  625.                         chalf.mSrc[0].mMapping = GL_UNSIGNED_INVERT_NV;
  626.                         chalf.mSrc[2].mMapping = GL_UNSIGNED_IDENTITY_NV;
  627.                         break;
  628.  
  629.                     default:
  630.                         errout.ThrowError(op.mLocation, "The first argument to 'lrp' can only use _sat and 1-reg modifiers");
  631.                     }
  632.                     chalf.mbDotAB = false;
  633.                     chalf.mbDotCD = false;
  634.                     chalf.mbMux = false;
  635.                     break;
  636.                 case kFSOpDp3:
  637.                     // dot(A.rgb, B.rgb)
  638.                     if (alphaOp)
  639.                         errout.ThrowError(op.mLocation, "'dp3' cannot be issued as an alpha instruction");
  640.                     chalf.mDst[0] = rdsts[0];
  641.                     chalf.mDst[1] = GL_DISCARD_NV;
  642.                     chalf.mDst[2] = GL_DISCARD_NV;
  643.                     chalf.mSrc[0] = rsrcs[0];
  644.                     chalf.mSrc[1] = rsrcs[1];
  645.                     chalf.mSrc[2].SetZero();
  646.                     chalf.mSrc[3].SetZero();
  647.                     chalf.mbDotAB = true;
  648.                     chalf.mbDotCD = false;
  649.                     chalf.mbMux = false;
  650.                     break;
  651.                 case kFSOpMma:
  652.                     chalf.mDst[0] = rdsts[0];
  653.                     chalf.mDst[1] = rdsts[1];
  654.                     chalf.mDst[2] = rdsts[2];
  655.                     chalf.mSrc[0] = rsrcs[0];
  656.                     chalf.mSrc[1] = rsrcs[1];
  657.                     chalf.mSrc[2] = rsrcs[2];
  658.                     chalf.mSrc[3] = rsrcs[3];
  659.                     chalf.mbDotAB = false;
  660.                     chalf.mbDotCD = false;
  661.                     chalf.mbMux = false;
  662.                     break;
  663.                 case kFSOpMms:
  664.                     chalf.mDst[0] = rdsts[0];
  665.                     chalf.mDst[1] = rdsts[1];
  666.                     chalf.mDst[2] = rdsts[2];
  667.                     chalf.mSrc[0] = rsrcs[0];
  668.                     chalf.mSrc[1] = rsrcs[1];
  669.                     chalf.mSrc[2] = rsrcs[2];
  670.                     chalf.mSrc[3] = rsrcs[3];
  671.                     chalf.mbDotAB = false;
  672.                     chalf.mbDotCD = false;
  673.                     chalf.mbMux = true;
  674.                     break;
  675.                 case kFSOpDm:
  676.                     if (alphaOp)
  677.                         errout.ThrowError("'dm' cannot be issued as an alpha instruction");
  678.                     chalf.mDst[0] = rdsts[0];
  679.                     chalf.mDst[1] = rdsts[1];
  680.                     chalf.mDst[2] = GL_DISCARD_NV;
  681.                     chalf.mSrc[0] = rsrcs[0];
  682.                     chalf.mSrc[1] = rsrcs[1];
  683.                     chalf.mSrc[2] = rsrcs[2];
  684.                     chalf.mSrc[3] = rsrcs[3];
  685.                     chalf.mbDotAB = true;
  686.                     chalf.mbDotCD = false;
  687.                     chalf.mbMux = false;
  688.                     break;
  689.                 case kFSOpDd:
  690.                     if (alphaOp)
  691.                         errout.ThrowError("'dd' cannot be issued as an alpha instruction");
  692.                     chalf.mDst[0] = rdsts[0];
  693.                     chalf.mDst[1] = rdsts[1];
  694.                     chalf.mDst[2] = GL_DISCARD_NV;
  695.                     chalf.mSrc[0] = rsrcs[0];
  696.                     chalf.mSrc[1] = rsrcs[1];
  697.                     chalf.mSrc[2] = rsrcs[2];
  698.                     chalf.mSrc[3] = rsrcs[3];
  699.                     chalf.mbDotAB = true;
  700.                     chalf.mbDotCD = true;
  701.                     chalf.mbMux = false;
  702.                     break;
  703.                 case kFSOpDda:
  704.                     if (alphaOp)
  705.                         errout.ThrowError("'dda' cannot be issued as an alpha instruction");
  706.                     chalf.mDst[0] = rdsts[0];
  707.                     chalf.mDst[1] = rdsts[1];
  708.                     chalf.mDst[2] = rdsts[2];
  709.                     chalf.mSrc[0] = rsrcs[0];
  710.                     chalf.mSrc[1] = rsrcs[1];
  711.                     chalf.mSrc[2] = rsrcs[2];
  712.                     chalf.mSrc[3] = rsrcs[3];
  713.                     chalf.mbDotAB = true;
  714.                     chalf.mbDotCD = true;
  715.                     chalf.mbMux = false;
  716.                     break;
  717.                 default:
  718.                     errout.ThrowError("Instruction not supported in this profile");
  719.             }
  720.  
  721.             if (alphaOp) {
  722.                 if (!allowAlpha)
  723.                     errout.ThrowError(op.mLocation, "Cannot use RGB argument in alpha operation");
  724.  
  725.                 if (combinerAlphaOp)
  726.                     errout.ThrowError(op.mLocation, "Cannot co-issue two alpha operations");
  727.  
  728.                 combinerAlphaOp = true;
  729.  
  730.                 RegisterCombinerHalf& calpha = pCombiner->mAlpha;
  731.                 calpha = chalf;
  732.  
  733.                 for(int i=0; i<4; ++i) {
  734.                     if (calpha.mSrc[i].mPortion == GL_RGBA)
  735.                         calpha.mSrc[i].mPortion = GL_ALPHA;
  736.                 }
  737.             }
  738.  
  739.             if (colorOp) {
  740.                 if (!allowColor)
  741.                     errout.ThrowError(op.mLocation, "Cannot use .b swizzle on color operation");
  742.  
  743.                 if (combinerColorOp)
  744.                     errout.ThrowError(op.mLocation, "Cannot co-issue two color operations");
  745.  
  746.                 combinerColorOp = true;
  747.  
  748.                 RegisterCombinerHalf& ccolor = pCombiner->mColor;
  749.                 ccolor = chalf;
  750.  
  751.                 for(int i=0; i<4; ++i) {
  752.                     if (ccolor.mSrc[i].mPortion == GL_RGBA)
  753.                         ccolor.mSrc[i].mPortion = GL_RGB;
  754.                 }
  755.             }
  756.         } else {
  757.             for(int i=0; i<7; ++i) {
  758.                 RegisterCombinerSrc& rsrc = config->mFinalCombiner.mSrc[i];
  759.                 
  760.                 rsrc = rsrcs[i];
  761.  
  762.                 switch(rsrc.mMapping) {
  763.                     case GL_SIGNED_IDENTITY_NV:        // we implicitly saturate, so we allow this
  764.                         rsrc.mMapping = GL_UNSIGNED_IDENTITY_NV;
  765.                         break;
  766.                     case GL_UNSIGNED_IDENTITY_NV:
  767.                     case GL_UNSIGNED_INVERT_NV:
  768.                         break;
  769.                     default:
  770.                         errout.ThrowError(op.mLocation, "Inputs to the final combiner must use unsigned saturation or complement");
  771.                         break;
  772.                 }
  773.  
  774.                 if (i < 6) {
  775.                     if (rsrc.mPortion == GL_RGBA)
  776.                         rsrc.mPortion = GL_RGB;
  777.  
  778.                     if (rsrc.mPortion == GL_BLUE)
  779.                         errout.ThrowError(op.mLocation, "Final combiner inputs A-F must use .a, .rgb, or .rgba (none) swizzle");
  780.                 } else {
  781.                     if (rsrc.mPortion == GL_RGB)
  782.                         errout.ThrowError(op.mLocation, "Final combiner input G must use .a, .b, or .rgba (none) swizzle");
  783.  
  784.                     if (rsrc.mPortion == GL_RGBA)
  785.                         rsrc.mPortion = GL_ALPHA;
  786.                 }
  787.             }
  788.         }
  789.  
  790.         ++it;
  791.         if (isFinalCombiner || it == itEnd || !it->mbCoIssue) {
  792.             // flush combiner
  793.             if (!isFinalCombiner) {
  794.                 ++config->mGeneralCombinerCount;
  795.                 ++pCombiner;
  796.             }
  797.  
  798.             constantStageMask = 0;
  799.             constantStageCount = 0;
  800.             combinerAlphaOp = false;
  801.             combinerColorOp = false;
  802.         }
  803.     }
  804.  
  805. #if 0
  806.     // dump combiners
  807.     for(int i=0; i<config->mConstantsUsed; ++i) {
  808.         printf("def c%d, %g, %g, %g, %g\n", i, config->mConstants[i][0], config->mConstants[i][1], config->mConstants[i][2], config->mConstants[i][3]);
  809.     }
  810.  
  811.     for(int i=0; i<config->mGeneralCombinerCount; ++i) {
  812.         const RegisterCombiner& comb = config->mGeneralCombiners[i];
  813.         int maxdst = 2;
  814.         bool coissue = false;
  815.  
  816.         for(int j=0; j<2; ++j) {
  817.             const RegisterCombinerHalf& chalf = j ? comb.mAlpha : comb.mColor;
  818.  
  819.             if (chalf.mDst[0] == GL_DISCARD_NV && chalf.mDst[1] == GL_DISCARD_NV && chalf.mDst[2] == GL_DISCARD_NV)
  820.                 continue;
  821.  
  822.             if (coissue)
  823.                 printf("+ ");
  824.             coissue = true;
  825.  
  826.             if (chalf.mbDotAB) {
  827.                 if (chalf.mbDotCD)
  828.                     printf("dd");
  829.                 else
  830.                     printf("dm");
  831.             } else {
  832.                 if (chalf.mbDotCD)
  833.                     printf("md");
  834.                 else {
  835.                     maxdst = 3;
  836.                     if (chalf.mbMux)
  837.                         printf("mms");
  838.                     else
  839.                         printf("mma");
  840.                 }
  841.             }
  842.  
  843.             if (chalf.mBias == GL_BIAS_BY_NEGATIVE_ONE_HALF_NV) {
  844.                 if (chalf.mScale == GL_SCALE_BY_TWO_NV)
  845.                     printf("_bx2");
  846.                 else
  847.                     printf("_bias");
  848.             } else {
  849.                 switch(chalf.mScale) {
  850.                     case GL_SCALE_BY_ONE_HALF_NV:
  851.                         printf("_d2");
  852.                         break;
  853.                     case GL_SCALE_BY_TWO_NV:
  854.                         printf("_x2");
  855.                         break;
  856.                     case GL_SCALE_BY_FOUR_NV:
  857.                         printf("_x4");
  858.                         break;
  859.                 }
  860.             }
  861.  
  862.             for(int k=0; k<maxdst; ++k) {
  863.                 if (k)
  864.                     putchar(',');
  865.  
  866.                 putchar(' ');
  867.  
  868.                 switch(chalf.mDst[k]) {
  869.                     case GL_DISCARD_NV:        printf("discard"); break;
  870.                     case GL_SPARE0_NV:        printf("r0"); break;
  871.                     case GL_SPARE1_NV:        printf("r1"); break;
  872.                     case GL_TEXTURE0_ARB:    printf("t0"); break;
  873.                     case GL_TEXTURE1_ARB:    printf("t1"); break;
  874.                     case GL_TEXTURE2_ARB:    printf("t2"); break;
  875.                     case GL_TEXTURE3_ARB:    printf("t3"); break;
  876.                 }
  877.  
  878.                 if (chalf.mDst[k] != GL_DISCARD_NV)
  879.                     printf(j ? ".a" : ".rgb");
  880.             }
  881.  
  882.             for(int k=0; k<4; ++k) {
  883.                 const RegisterCombinerSrc& rsrc = chalf.mSrc[k];
  884.  
  885.                 printf(", ");
  886.  
  887.                 rsrc.Print(j ? GL_ALPHA : GL_RGB);
  888.             }
  889.  
  890.             putchar('\n');
  891.         }
  892.     }
  893.  
  894.     printf("final");
  895.     for(int i=0; i<7; ++i) {
  896.         if (i)
  897.             putchar(',');
  898.         putchar(' ');
  899.         config->mFinalCombiner.mSrc[i].Print(i == 6 ? GL_ALPHA : GL_RGB);
  900.     }
  901.     putchar('\n');
  902. #endif
  903.  
  904.     return config.release();
  905. }
  906.